import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_skeleton/shimmer_view.dart';
import 'package:flutter_skeleton/skeleton_animation.dart';

/**
 *
 * @ProjectName:    flutter_skeleton
 * @Package:
 * @ClassName:      skeleton_view
 * @Description:    骨架屏view
 * @Author:         孙浩
 * @CreateDate:     4/29/21 2:14 PM
 */
class SkeletonContainerView extends StatefulWidget {
  final Widget child;
  final bool isLoading;
  double minWidth;
  Duration animDuration;
  final Duration splashDuration;
  final Color color;
  final Gradient gradient;
  final BorderRadius radius;
  SkeletonAnimationStyle animationStyle;

  SkeletonContainerView(
      {@required this.child,
      @required this.isLoading,
      this.minWidth,
      this.animationStyle = SkeletonAnimationStyle.shimmer,
      this.animDuration,
      this.color = Colors.grey,
      this.splashDuration,
      this.gradient,
      this.radius});

  @override
  _SkeletonViewState createState() {
    return _SkeletonViewState();
  }
}

///
/// @ProjectName:    flutter_skeleton
/// @Package:
/// @ClassName:      _RealView
/// @Description:    dart类作用
/// @Author:         孙浩
/// @CreateDate:     2021-04-30 17:35:09
class _RealView extends StatefulWidget {
  final Widget child;
  final Duration duration;

  _RealView(this.child, this.duration);

  @override
  State<StatefulWidget> createState() {
    return _ChildInnerView();
  }
}

class _ChildInnerView extends State<_RealView> with TickerProviderStateMixin {
  AnimationController _innerController;

  @override
  void initState() {
    super.initState();
    _innerController = AnimationController(
        vsync: this, duration: widget.duration ?? Duration(milliseconds: 1500))
      ..addListener(() {
        setState(() {});
      });
    _innerController.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _innerController.dispose();
      }
    });
    _innerController.forward(from: 0);
  }

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: _innerController.value,
      child: widget.child,
    );
  }
}

class _SkeletonViewState extends State<SkeletonContainerView>
    with TickerProviderStateMixin {
  double minWidth;
  SkeletonAnimationManager manager;

  @override
  void initState() {
    super.initState();
    print("${widget.isLoading}");
    minWidth = widget.minWidth;
    if (widget.animationStyle == SkeletonAnimationStyle.static) {
      return;
    }
    if (manager == null) {
      manager = SkeletonAnimationManager()
        ..initAnimContainer(this,
            duration: widget.animDuration ?? Duration(seconds: 2),
            change: (value) {
          setState(() {});
        });
      manager.start(
          reverse: widget.animationStyle == SkeletonAnimationStyle.widthChange);
    }

    if (!widget.isLoading) {
      manager?.cancel();
    }
  }

  @override
  Widget build(BuildContext context) {
    if (!widget.isLoading) {
      manager?.cancel();
    }
    return Container(
      width: widget.isLoading ? double.infinity : null,
      child: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints constraints) {
        if (widget.animationStyle == SkeletonAnimationStyle.widthChange &&
            minWidth == null) {
          minWidth = constraints.maxWidth / 10;
        }
        if (!widget.isLoading)
          return _RealView(widget.child, widget.splashDuration);
        if (widget.animationStyle == SkeletonAnimationStyle.shimmer)
          return buildShimmer(constraints);
        if (widget.animationStyle == SkeletonAnimationStyle.widthChange)
          return Row(
            children: [buildChild(constraints)],
          );
        return buildChild(constraints);
      }),
    );
  }

  Shimmer buildShimmer(BoxConstraints constraints) {
    return Shimmer(
      manager.animationController,
      child: buildChild(constraints),
      period: widget.animDuration,
      gradient: widget.gradient ??
          LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.centerRight,
              colors: <Color>[
                Colors.grey[300],
                Colors.grey[300],
                Colors.grey[100],
                Colors.grey[300],
                Colors.grey[300]
              ],
              stops: const <double>[
                0.0,
                0.35,
                0.5,
                0.65,
                1.0
              ]),
    );
  }

  Container buildChild(BoxConstraints constraints) {
    return Container(
      decoration: BoxDecoration(
          color: widget.isLoading ? widget.color : Colors.transparent,
          borderRadius: widget.radius),
      width: widget.animationStyle == SkeletonAnimationStyle.static
          ? null
          : getWidth(constraints),
      child: AnimatedOpacity(
        duration: Duration(seconds: 200),
        opacity: widget.isLoading ? 0 : 1,
        child: widget.child,
      ),
    );
  }

  ///获取宽度
  double getWidth(BoxConstraints constraints) {
    try {
      return minWidth +
          manager.animationController.value * (constraints.maxWidth - minWidth);
    } catch (e) {
      return 100;
    }
  }

  void stopAnimate() {
    manager.cancel();
  }

  @override
  void dispose() {
    super.dispose();
    manager.cancel();
  }
}
